<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GUI }  from "three/examples/jsm/libs/lil-gui.module.min.js";
import Stats from "three/examples/jsm/libs/stats.module";
import { ref, onMounted } from "vue";
import { ConvexGeometry } from "three/examples/jsm/geometries/ConvexGeometry";
import { ParametricGeometry } from "three/examples/jsm/geometries/ParametricGeometry";
import { ParametricGeometries } from "three/examples/jsm/geometries/ParametricGeometries";

// 画布
const canvas = ref<any>('');
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(-50, 30, 20);
camera.lookAt(-10, 0, 0);
// 平面
const planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
const planeMaterial = new THREE.MeshLambertMaterial({
  color: 0xffffff,
  side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(0, 0, 0);
plane.receiveShadow = true;
scene.add(plane);
// 添加其他几何体
const addGeometries = () => {
  const geometries = [];
  // 圆柱体
  geometries.push(new THREE.CylinderGeometry(1, 4, 4));
  // 立方体
  geometries.push(new THREE.BoxGeometry(2, 2, 2));
  // 球体
  geometries.push(new THREE.SphereGeometry(2));
  // 二十面体
  geometries.push(new THREE.IcosahedronGeometry(4));
  // 凸
  const points = [
    new THREE.Vector3(2, 2, 2),
    new THREE.Vector3(2, 2, -2),
    new THREE.Vector3(-2, 2, -2),
    new THREE.Vector3(-2, 2, 2),
    new THREE.Vector3(2, -2, 2),
    new THREE.Vector3(2, -2, -2),
    new THREE.Vector3(-2, -2, -2),
    new THREE.Vector3(-2, -2, 2)
  ];
  geometries.push(new ConvexGeometry(points));
  // 板条
  const pts = []; // points array - the path profile points will be stored here
  const detail = .1; // half-circle detail - how many angle increments will be used to generate points
  const radius = 3; // radius for half_sphere
  for (let angle = 0.0; angle < Math.PI; angle += detail) {
    //loop from 0.0 radians to PI (0 - 180 degrees)
    pts.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius)); //angle/radius to x,z
  }
  geometries.push(new THREE.LatheGeometry(pts, 12));
  // 八面体
  geometries.push(new THREE.OctahedronGeometry(3));
  // 参数化几何体，根据传入的公式,计算出相应的几何体 - 这里是生成莫比乌斯环
  geometries.push(new ParametricGeometry(ParametricGeometries.mobius3d, 20, 10));
  // 四面体
  geometries.push(new THREE.TetrahedronGeometry(3));
  // 圆环
  geometries.push(new THREE.TorusGeometry(3, 1, 10, 10));
  // 圆环结
  geometries.push(new THREE.TorusKnotGeometry(3, 0.5, 50, 20));

  let j = 0;
  for (let i = 0; i < geometries.length; i++) {
    const materials = [
      new THREE.MeshLambertMaterial({
        color: Math.random() * 0xffffff
      }),
      new THREE.MeshBasicMaterial({
        color: 0x000000,
        wireframe: true,
      })
    ];

    const mesh = new THREE.Group();
    for (let k = 0; k < materials.length; k++) {
      mesh.add(new THREE.Mesh(geometries[i], materials[k]));
    }
    mesh.traverse( (e) => {
      e.castShadow = true
    });
    mesh.position.set(-24 + ((i % 4) * 12), 4, -8 + (j * 12));

    if ((i + 1) % 4 == 0) {
      j++;
    }
    scene.add(mesh);
  }
};
addGeometries();

// 光源
const ambientLight = new THREE.AmbientLight(0x555555);
const spotLight = new THREE.SpotLight(0xffffff, 1.2, 150, Math.PI / 4, 0, 2);
spotLight.position.set(-40, 30, 30);
spotLight.castShadow = true;
spotLight.shadow.mapSize = new THREE.Vector2(window.innerWidth, window.innerHeight);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
scene.add(ambientLight, spotLight);
// 渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.shadowMap.enabled = true;
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
orbitControl.update();
// 性能统计
const stat = Stats();
stat.setMode(0);
// gui界面
const gui = new GUI();
/**
 * 渲染函数
 */
const render = () => {
  stat.update();

  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

onMounted(() => {
  canvas.value.appendChild(renderer.domElement);
  canvas.value.appendChild(stat.domElement);
  render();
})
</script>

<style scoped>
body{
  margin: 0;
  overflow: hidden;
}
</style>
